
#ifdef _MSC_VER
#include <windows.h>
#else 
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#endif

#include "../os_thread.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//#include <malloc.h>

#ifdef _MSC_VER

#else 

pthread_mutex_t 	g_mutex_l = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t      g_cond = PTHREAD_COND_INITIALIZER;

#endif




thread_ctx* thread_create1(void * callback, void * lpParam, char * eventName)
{
#ifdef _MSC_VER
	DWORD threadID;
	HANDLE hThread;
	thread_ctx * ctx = NULL;

	hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)callback, lpParam, 0, &threadID);
	if (hThread == NULL)
	{
		return NULL;
	}

	ctx = malloc(sizeof(thread_ctx));
	ctx->param = lpParam;
	ctx->thread_handle = hThread;
	ctx->wait_event = CreateEvent(NULL, FALSE, FALSE, eventName);
	ctx->state = THREAD_STATE_STARTED;

	return ctx;
	
#else 
	thread_ctx * ctx = NULL;
	pthread_t hThread;

	pthread_mutex_init(&g_mutex_l, NULL);
	pthread_cond_init(&g_cond, NULL);


	int nRet = pthread_create(&hThread, NULL, (void* (*)(void*))callback, lpParam);

	if (nRet != 0) //error
	{
		return NULL;
	}

	ctx = (thread_ctx*)malloc(sizeof(thread_ctx));
	ctx->param = lpParam;
	ctx->thread_handle = hThread;
	ctx->state = THREAD_STATE_STARTED;

	return ctx;
#endif

	
}

long thread_wait(thread_ctx* ctx, long timeOut)
{
#ifdef _MSC_VER

	DWORD dwResult = 0;
	long ret = 0;
	HWND hEvent = (HANDLE)ctx->wait_event;

	if (ctx == NULL) return THREAD_WAIT_FAILED;

	dwResult = WaitForSingleObject(hEvent, timeOut);
	switch (dwResult)
	{
	case WAIT_OBJECT_0:
		ret = THREAD_WAIT_EXIT;
		break;
	case WAIT_TIMEOUT:
		ret = THREAD_WAIT_TIMEOUT;
		break;
	default:
		ret = THREAD_WAIT_EXIT;
		break;
	}

	if (ctx->state == THREAD_STATE_NOTSTARTED)
	{
		ret = THREAD_WAIT_EXIT;
	}

	return ret;

#else 
	int nRet = 0;
	struct timespec timeout = { 0 };
	timeout.tv_sec = time(NULL) + (timeOut / 1000);
	timeout.tv_nsec = 0;

	if (ctx->state == THREAD_STATE_NOTSTARTED)
	{
		return THREAD_WAIT_EXIT;
	}

	pthread_mutex_lock(&g_mutex_l);
	nRet = pthread_cond_timedwait(&g_cond, &g_mutex_l, &timeout);
	if (nRet == 0)
	{
		pthread_mutex_unlock(&g_mutex_l);
		return THREAD_WAIT_EXIT;
	}

	if (nRet == 110)
	{
		pthread_mutex_unlock(&g_mutex_l);
		return THREAD_WAIT_TIMEOUT;
	}

	pthread_mutex_unlock(&g_mutex_l);
	return THREAD_WAIT_FAILED;
#endif
	
}

long thread_exit(thread_ctx * ctx)
{
#ifdef _MSC_VER
	long count = 0;
	DWORD exitCode = 0;
	if (ctx == NULL) return 0;

	ctx->state = THREAD_STATE_NOTSTARTED;
	if (ctx->wait_event != 0)
	{
		SetEvent(ctx->wait_event); //trigger to exit
	}

	GetExitCodeThread(ctx->thread_handle, &exitCode);

	while (exitCode == STILL_ACTIVE && count < 10)
	{
		GetExitCodeThread(ctx->thread_handle, &exitCode);
		thread_sleep(100);
		count++;
	}

	if (ctx->wait_event != 0)
	{
		CloseHandle(ctx->wait_event);
		//ctx->wait_event = 0;
	}

	if (exitCode == STILL_ACTIVE)
	{
		TerminateThread(ctx->thread_handle, 0);
	}

	if (ctx->thread_handle != 0)
	{
		CloseHandle(ctx->thread_handle);
		ctx->thread_handle = 0;
	}

	return exitCode;
#else 
	int exitCode = 0;

	ctx->state = THREAD_STATE_NOTSTARTED;

	pthread_cond_signal(&g_cond);
	int ret = pthread_join(ctx->thread_handle, NULL);
	{

	}

	pthread_cond_destroy(&g_cond);

	pthread_mutex_destroy(&g_mutex_l);

	ctx->thread_handle = 0;
	return exitCode;
#endif
	
}


long thread_terminate1(thread_ctx * ctx)
{
#ifdef _MSC_VER
	if (ctx->thread_handle != 0)
	{
		thread_exit(ctx);
	}
	if (ctx) free(ctx);

	return 0;

#else 
	free(ctx);
	return 0;
#endif

}

long thread_sleep(long interval)
{
#ifdef _MSC_VER
	Sleep(interval);
	return 0;
#else 
	usleep(interval * 1000);
	return 0;
#endif
	
}

long thread_exist(thread_ctx * ctx, char * eventName)
{
#ifdef _MSC_VER
	HANDLE evtHandle = OpenEvent(SYNCHRONIZE, FALSE, eventName);
	if (evtHandle != NULL)
	{
		CloseHandle(evtHandle);
		return 1;
	}
	return 0;
#else 
	if (ctx == 0) return 0;
	if (ctx->thread_handle != 0) return 1;
	return 0;
#endif
	
}

